package com.yami.shop.consign.common.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.app.dto.OrderConsignDto;
import com.yami.shop.bean.app.dto.OrderConsignUserDto;
import com.yami.shop.bean.dto.AuditParam;
import com.yami.shop.bean.dto.ConsignDTO;
import com.yami.shop.bean.dto.ConsignParam;
import com.yami.shop.bean.enums.ConsignStatus;
import com.yami.shop.bean.enums.ProdConsignStatus;
import com.yami.shop.bean.event.AssetTrendsEvent;
import com.yami.shop.bean.model.ChannelUserRelationRecord;
import com.yami.shop.bean.model.ProdNft;
import com.yami.shop.bean.model.Product;
import com.yami.shop.bean.model.User;
import com.yami.shop.bean.vo.AssetTrendsVO;
import com.yami.shop.bean.vo.ConsignNumVO;
import com.yami.shop.bean.vo.ConsignRecordVO;
import com.yami.shop.bean.vo.ConsignSituationVO;
import com.yami.shop.common.bean.PageDTO;
import com.yami.shop.common.bean.PageVO;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.util.PageUtil;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.common.util.StringUtils;
import com.yami.shop.consign.common.dao.ConsignSituationMapper;
import com.yami.shop.consign.common.model.ConsignAuditRecord;
import com.yami.shop.consign.common.model.ConsignRecord;
import com.yami.shop.consign.common.model.ConsignSituation;
import com.yami.shop.consign.common.model.ProdConfig;
import com.yami.shop.consign.common.service.*;
import com.yami.shop.personnft.common.model.PersonNft;
import com.yami.shop.service.ChannelUserRelationRecordService;
import com.yami.shop.personnft.common.service.PersonNftAccountService;
import com.yami.shop.personnft.common.service.PersonNftService;
import com.yami.shop.security.common.bo.UserInfoInTokenBO;
import com.yami.shop.security.common.util.AuthUserContext;
import com.yami.shop.service.ProdNftService;
import com.yami.shop.service.ProductService;
import com.yami.shop.service.SysConfigService;
import com.yami.shop.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ConsignSituationServiceImpl extends ServiceImpl<ConsignSituationMapper, ConsignSituation> implements ConsignSituationService {

    private static final String CHECK_CONSIGN_UPDATE_PREFIX = "mallcloud_consign:update:";

    @Autowired
    private ConsignSituationMapper consignSituationMapper;

    @Autowired
    private ProdConfigService prodConfigService;

    @Autowired
    private ConsignRecordService consignRecordService;

    @Autowired
    private ConsignAnalysisService consignAnalysisService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private ConsignAuditRecordService consignAuditRecordService;

    @Autowired
    private UserService userService;

    @Autowired
    private PersonNftService personNftService;

    @Autowired
    private ProductService productService;

    @Autowired
    private ProdNftService prodNftService;

    @Autowired
    private SysConfigService sysConfigService;

    @Autowired
    private ChannelUserRelationRecordService channelUserRelationService;

    @Autowired
    private PersonNftAccountService personNftAccountService;




    /**
     * 我的寄售
     *
     * @param pageDTO
     * @param status
     * @param userId
     * @return
     */
    @Override
    public PageVO<ConsignSituationVO> getConsignPage(PageDTO pageDTO, List<Integer> status, String userId) {
        ConsignSituation consign = new ConsignSituation();
        consign.setStatusList(status);
        consign.setUserId(userId);
        PageVO<ConsignSituationVO> pageVO = PageUtil.doPage(pageDTO, () -> consignSituationMapper.consignList(consign));
        if (status.contains(ConsignStatus.SOLD.getValue())) {
            List<ConsignSituationVO> list = pageVO.getList();
            list.stream().forEach(c -> {
                ConsignRecord one = consignRecordService.getOne(new LambdaQueryWrapper<ConsignRecord>().eq(ConsignRecord::getConsignId, c.getId()).eq(ConsignRecord::getType, 1));
                ConsignRecordVO recordVO = BeanUtil.copyProperties(one, ConsignRecordVO.class);
                if(Objects.nonNull(recordVO)){
                    User user = userService.getUserByUserId(recordVO.getUserId());
                    recordVO.setUserName(user.getNickName());
                    recordVO.setPic(user.getPic());
                    c.setRecordVO(recordVO);
                }
            });
        }
        if (status.containsAll(Arrays.asList(ConsignStatus.SHOPREJECT.getValue(), ConsignStatus.PLATREJECT.getValue()))) {
            List<ConsignSituationVO> list = pageVO.getList();
            list.stream().forEach(c -> {
                ConsignAuditRecord one = consignAuditRecordService.getOne(new LambdaQueryWrapper<ConsignAuditRecord>().eq(ConsignAuditRecord::getConsignId, c.getId()).eq(ConsignAuditRecord::getStatus, 2).orderByDesc(ConsignAuditRecord::getCreateTime).last("limit 1"));
                if(Objects.nonNull(one)){
                    c.setAuditTime(one.getCreateTime());
                    c.setAuditReason(one.getAuditReason());
                }
            });
        }
        return pageVO;
    }

    /**
     * 寄售列表
     *
     * @param pageDTO
     * @param consign
     * @return
     */
    @Override
    public PageVO<ConsignSituationVO> getPage(PageDTO pageDTO, ConsignSituation consign) {
        PageVO<ConsignSituationVO> pageVO = PageUtil.doPage(pageDTO, () -> consignSituationMapper.consignList(consign));
        List<ConsignSituationVO> list = pageVO.getList();
        list.stream().forEach(a -> {
            User user = userService.getUserByUserId(a.getUserId());
            a.setUserName(user.getNickName());
        });
        return pageVO;
    }

    /**
     * 批量寄售
     *
     * @param param
     */
    @Override
    @Transactional
    public void submitConsign(ConsignParam param) {
        String lockKey = "lock_isConsignKey";
        // 获取到redisson锁对象
        RLock redissonLock = redissonClient.getLock(lockKey);
        String userId = param.getUserId();
        // 交易密码验证
        try {
            redissonLock.lock();
            // 寄售数据
            List<ConsignDTO> consigns = param.getConsigns();
            if (CollUtil.isEmpty(consigns)) {
                throw new YamiShopBindException("请选择要寄售的持仓商品！");
            }
            Map<String, Integer> map = consigns.stream().collect(Collectors.toMap(ConsignDTO::getPositionId, ConsignDTO::getPrice));
            Set<String> strings = map.keySet();
            List<String> positionIds = new ArrayList<String>(strings);
            log.info("提交批量寄售，持仓ids：" + positionIds.toString());
            for (String positionId : positionIds) {
                if (RedisUtil.hasKey("mallcloud:consign:submit:positionId" + "-" + positionId)) {
                    log.error("重复提交：" + positionId);
                    throw new YamiShopBindException("异常请求，重复提交！");
                }
            }
            // 持仓
            List<PersonNft> positionList = personNftService.getPersonNftList(positionIds);
            for (PersonNft position : positionList) {
                if (position.getStatus() != 0) {
                    log.error("持仓状态异常" + position.getId());
                    throw new YamiShopBindException("只有正常持仓才可寄售");
                }
                if (!position.getUserId().equals(userId)) {
                    throw new YamiShopBindException("非法数据！");
                }
            }
            Long productId = positionList.get(0).getProductId();
            ProdConfig prodConfig = prodConfigService.getOne(new LambdaQueryWrapper<ProdConfig>().eq(ProdConfig::getProdId, productId.intValue()).ne(ProdConfig::getStatus, ProdConsignStatus.DELETE.getValue()));
            if (Objects.isNull(prodConfig) || prodConfig.getStatus() != ProdConsignStatus.OPEN.getValue()) {
                throw new YamiShopBindException("该商品未开启寄售！");
            }
            Collection<Integer> values = map.values();
            Integer max = Collections.max(values);
            Integer min = Collections.min(values);
            if (max > prodConfig.getHighPrice()) {
                throw new YamiShopBindException("不得超过该商品最高寄售价！");
            }
            if (min < prodConfig.getLowPrice()) {
                throw new YamiShopBindException("不得低于该商品最低寄售价！");
            }
            Product product = productService.getById(productId);
            String chainCode = product.getChannelCode();
            String shopId = product.getShopId().toString();
            Integer shopAuditType = getShopAuditType(shopId);
            Integer auditType = getAuditType();
            Integer status = setStatusByShopAuditType(shopAuditType, auditType);
            List<ConsignSituation> list = new ArrayList<>();
            positionList.stream().forEach(p -> {
                ConsignSituation consign = getConsignSituation(userId, map, shopAuditType, auditType, p, shopId, status,product);
                list.add(consign);
            });
            saveBatch(list);
            personNftService.updatePersonNftStatus(positionIds, 1);
            if (shopAuditType == ConsignStatus.AUTOMATIC.getValue() || auditType == ConsignStatus.AUTOMATIC.getValue()) {
                // 保存自动审核记录
                saveAuditRecords(shopAuditType, auditType, list);
            }
            if (status == ConsignStatus.CONSIGNMENT.getValue()) {
                // 免审核或自动审核-保存寄售记录
                saveRecords(userId, list);
                // 资产转移到担保账户
                transferToGuarantee(list);
            }
            for (String positionId : positionIds) {
                RedisUtil.set("mallcloud:consign:submit:positionId" + "-" + positionId, userId, 0);
            }
        } catch (Exception e) {
            log.error("批量寄售异常：", e);
            String message = e.getMessage().length() > 14 ? "系统繁忙" : e.getMessage();
            throw new YamiShopBindException(message);
        } finally {
            // ============= 释放redisson锁 ==========
            redissonLock.unlock();
        }
    }

    /**
     * 根据平台审核开关获取平台审核类型
     *
     * @return
     */
    private Integer getAuditType() {
        Integer auditType = ConsignStatus.EXEMPT.getValue();
        String consignPlatAudit = sysConfigService.getValue("CONSIGN_PLAT_AUDIT");
        if (Objects.equals(consignPlatAudit, "true")) {
            auditType = ConsignStatus.MANUAL.getValue();
            String platAutoAudit = sysConfigService.getValue("CONSIGN_AUTO_AUDIT");
            if (Objects.equals(platAutoAudit, "true")) {
                auditType = ConsignStatus.AUTOMATIC.getValue();
            }
        }
        return auditType;
    }

    /**
     * 根据商户审核开关获取商户审核类型
     *
     * @param shopId
     * @return
     */
    private Integer getShopAuditType(String shopId) {
        Integer shopAuditType = ConsignStatus.EXEMPT.getValue();
        String consignShopAudit = sysConfigService.getValue("CONSIGN_SHOP_AUDIT");
        if (Objects.equals(consignShopAudit, "true")) {
            shopAuditType = ConsignStatus.MANUAL.getValue();
            String shopAutoAudit = sysConfigService.getValue("CONSIGN_AUTO_AUDIT_" + shopId);
            if (Objects.equals(shopAutoAudit, "true")) {
                shopAuditType = ConsignStatus.AUTOMATIC.getValue();
            }
        }
        return shopAuditType;
    }


    /**
     * 保存审核记录
     *
     * @param shopAuditType
     * @param auditType
     * @param consigns
     */
    private void saveAuditRecords(Integer shopAuditType, Integer auditType, List<ConsignSituation> consigns) {
        List<ConsignAuditRecord> auditRecords = new ArrayList<>();
        consigns.stream().forEach(c -> {
            if (shopAuditType == ConsignStatus.AUTOMATIC.getValue()) {
                ConsignAuditRecord auditRecord = new ConsignAuditRecord();
                auditRecord.setConsignId(c.getId());
                auditRecord.setType(ConsignStatus.SHOP.getValue());
                auditRecord.setPrice(c.getPrice());
                auditRecord.setStatus(1);
                auditRecord.setCreateTime(new Date());
                auditRecords.add(auditRecord);
            }
            if (shopAuditType != ConsignStatus.MANUAL.getValue() && auditType == ConsignStatus.AUTOMATIC.getValue()) {
                ConsignAuditRecord auditRecord = new ConsignAuditRecord();
                auditRecord.setConsignId(c.getId());
                auditRecord.setType(ConsignStatus.PLAT.getValue());
                auditRecord.setPrice(c.getPrice());
                auditRecord.setStatus(1);
                auditRecord.setCreateTime(new Date());
                auditRecords.add(auditRecord);
            }
        });
        consignAuditRecordService.saveBatch(auditRecords);
    }

    /**
     * 寄售申请
     *
     * @param userId
     * @param map
     * @param shopAuditType
     * @param auditType
     * @param p
     * @param product
     * @return
     */
    private ConsignSituation getConsignSituation(String userId, Map<String, Integer> map, Integer shopAuditType, Integer auditType, PersonNft p, String shopId, Integer status, Product product) {
        ConsignSituation consign = new ConsignSituation();
        consign.setProdId(p.getProductId().intValue());
        consign.setShopId(shopId);
        consign.setProdName(product.getProdName());
        consign.setImg(product.getPic());
        consign.setCode(p.getDawProductCode());
        consign.setDenomId(p.getDenomId());
        consign.setTokenId(p.getTokenId());
        consign.setPositionId(p.getId());
        consign.setPrice(map.get(p.getId()));
        consign.setShopAuditType(shopAuditType);
        consign.setAuditType(auditType);
        consign.setSellStatus(0);
        consign.setUserId(userId);
        consign.setStatus(status);
        if (status == ConsignStatus.CONSIGNMENT.getValue()) {
            consign.setAuditTime(new Date());
        }
        return consign;
    }

    /**
     * 由审核类型获取寄售状态
     *
     * @param shopAuditType
     * @param auditType
     * @return
     */
    private Integer setStatusByShopAuditType(Integer shopAuditType, Integer auditType) {
        if (shopAuditType == ConsignStatus.MANUAL.getValue()) {
            return ConsignStatus.SHOPWAIT.getValue();
        } else {
            return setStatusByAuditType(auditType);
        }
    }

    private Integer setStatusByAuditType(Integer auditType) {
        if (auditType == ConsignStatus.MANUAL.getValue()) {
            return ConsignStatus.PLATWAIT.getValue();
        } else {
            return ConsignStatus.CONSIGNMENT.getValue();
        }
    }

    /**
     * 自动审核 寄售记录保存
     *
     * @param userId
     * @param list
     * @return
     */
    private void saveRecords(String userId, List<ConsignSituation> list) {
        List<ConsignRecord> records = new ArrayList<>();
        for (ConsignSituation consign : list) {
            ConsignRecord record = new ConsignRecord();
            record.setUserId(Objects.isNull(userId) ? consign.getUserId() : userId);
            record.setType(0);
            record.setCode(consign.getCode());
            record.setPrice(Long.valueOf(consign.getPrice()));
            record.setNftId(consign.getTokenId());
            record.setProdId(consign.getProdId());
            record.setConsignId(consign.getId());
            records.add(record);
        }
        consignRecordService.saveBatch(records);
    }


    /**
     * 我的寄售详情
     *
     * @param id
     * @return
     */
    @Override
    public ConsignSituationVO getDetail(Long id) {
        ConsignSituation consign = getById(id);
        ConsignSituationVO consignVO = BeanUtil.copyProperties(consign, ConsignSituationVO.class);
        if (consignVO.getStatus() == ConsignStatus.CONSIGNMENT.getValue()) {
            User user = userService.getUserByUserId(consignVO.getUserId());
            consignVO.setUserName(user.getNickName());
            consignVO.setPic(user.getPic());
        } else if (consignVO.getStatus() == ConsignStatus.SOLD.getValue()) {
            ConsignRecord one = consignRecordService.getOne(new LambdaQueryWrapper<ConsignRecord>().eq(ConsignRecord::getConsignId, id).eq(ConsignRecord::getType, 1));
            ConsignRecordVO recordVO = BeanUtil.copyProperties(one, ConsignRecordVO.class);
            User user = userService.getUserByUserId(consignVO.getUserId());
            recordVO.setUserName(user.getNickName());
            recordVO.setPic(user.getPic());
            consignVO.setRecordVO(recordVO);
        } else if (consignVO.getStatus() == ConsignStatus.SHOPREJECT.getValue() || consignVO.getStatus() == ConsignStatus.PLATREJECT.getValue()) {
            ConsignAuditRecord one = consignAuditRecordService.getOne(new LambdaQueryWrapper<ConsignAuditRecord>().eq(ConsignAuditRecord::getConsignId, consignVO.getId()).eq(ConsignAuditRecord::getStatus, 2).orderByDesc(ConsignAuditRecord::getCreateTime).last("limit 1"));
            consignVO.setAuditTime(one.getCreateTime());
            consignVO.setAuditReason(one.getAuditReason());
        }
        return consignVO;
    }

    /**
     * 寄售修改，重新发布
     *
     * @param situation
     */
    @Override
    @Transactional
    public void updateConsignById(ConsignSituation situation) {
        ConsignSituation one = getById(situation.getId());
        if(!one.getUserId().equals(situation.getUserId())){
            throw new YamiShopBindException("非法数据");
        }
        Integer oldStatus = one.getStatus();
        if (oldStatus == ConsignStatus.CANCEL.getValue()) {
            throw new YamiShopBindException("已取消，不能操作！");
        }
        int updateNum = 0;
        if (oldStatus != ConsignStatus.SHOPREJECT.getValue() && oldStatus != ConsignStatus.PLATREJECT.getValue()) {
            if (RedisUtil.hasKey(CHECK_CONSIGN_UPDATE_PREFIX + situation.getId())) {
                updateNum = RedisUtil.get(CHECK_CONSIGN_UPDATE_PREFIX + situation.getId());
            }
            String num = sysConfigService.getValue("CONSIGN_UPDATE_NUM");
            if (StringUtils.isNotEmpty(num) && updateNum >= Integer.parseInt(num)) {
                throw new YamiShopBindException("寄售商品每天最多可修改" + num + "次！");
            }
        }
        if (oldStatus == ConsignStatus.SOLD.getValue()) {
            throw new YamiShopBindException("已出售，不能修改！");
        }
        if (one.getSellStatus() != 0) {
            throw new YamiShopBindException("锁定中，不能修改！");
        }
        ProdConfig prodConfig = prodConfigService.getOne(new LambdaQueryWrapper<ProdConfig>().eq(ProdConfig::getProdId, one.getProdId()).ne(ProdConfig::getStatus, ProdConsignStatus.DELETE.getValue()));
        if (Objects.isNull(prodConfig) || prodConfig.getStatus() != ProdConsignStatus.OPEN.getValue()) {
            throw new YamiShopBindException("该商品未开启寄售！");
        }
        if (situation.getPrice() > prodConfig.getHighPrice()) {
            throw new YamiShopBindException("不得超过该商品最高寄售价！");
        }
        if (situation.getPrice() < prodConfig.getLowPrice()) {
            throw new YamiShopBindException("不得低于该商品最低寄售价！");
        }
        Integer status = setStatusByShopAuditType(one.getShopAuditType(), one.getAuditType());
        one.setStatus(status);
        one.setPrice(situation.getPrice());
        one.setUpdateTime(new Date());
        updateById(one);
        if (one.getShopAuditType() == ConsignStatus.AUTOMATIC.getValue() || one.getAuditType() == ConsignStatus.AUTOMATIC.getValue()) {
            // 保存自动审核记录
            saveAuditRecords(one.getShopAuditType(), one.getAuditType(), Arrays.asList(one));
        }
        if (status == ConsignStatus.CONSIGNMENT.getValue()) {
            // 寄售记录
            ConsignRecord record = new ConsignRecord();
            record.setUserId(one.getUserId());
            record.setType(0);
            record.setCode(one.getCode());
            record.setPrice(Long.valueOf(situation.getPrice()));
            record.setNftId(one.getTokenId());
            record.setConsignId(one.getId());
            record.setProdId(one.getProdId());
            consignRecordService.save(record);
        }
        // 缓存修改标记
        if (oldStatus != ConsignStatus.SHOPREJECT.getValue() && oldStatus != ConsignStatus.PLATREJECT.getValue()) {
            updateNum++;
            RedisUtil.set(CHECK_CONSIGN_UPDATE_PREFIX + situation.getId(), updateNum, getSeconds());
        }
    }

    /**
     * 获取今日剩余秒数
     *
     * @return
     */
    private long getSeconds() {
        LocalDateTime midnight = LocalDateTime.now().plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
        return ChronoUnit.SECONDS.between(LocalDateTime.now(), midnight);
    }

    @Override
    @Transactional
    public void cancelConsignById(Long id, String userId) {
        ConsignSituation situation = getById(id);
        if(!userId.equals(situation.getUserId())){
            throw new YamiShopBindException("非法数据");
        }
        Integer oldStatus = situation.getStatus();
        if (oldStatus == ConsignStatus.CANCEL.getValue()) {
            throw new YamiShopBindException("已取消，不能操作！");
        }
        if (oldStatus != ConsignStatus.SHOPREJECT.getValue() && oldStatus != ConsignStatus.PLATREJECT.getValue()) {
            String limitDays = sysConfigService.getValue("CONSIGN_CANCEL_LIMIT_DAYS");
            if (StringUtils.isNotEmpty(limitDays)) {
                DateTime cancellableDate = DateUtil.offsetDay(situation.getAuditTime(), Integer.parseInt(limitDays));
                if (!cancellableDate.before(DateUtil.date())) {
                    throw new YamiShopBindException("未到可取消时间！");
                }
            }
        }
        if (oldStatus == ConsignStatus.SOLD.getValue()) {
            throw new YamiShopBindException("已出售，不能取消！");
        }
        if (situation.getSellStatus() != 0) {
            throw new YamiShopBindException("锁定中，不能取消！");
        }
        situation.setUserId(situation.getUserId());
        situation.setStatus(ConsignStatus.CANCEL.getValue());
        updateById(situation);
        // 取消寄售记录
        ConsignRecord record = new ConsignRecord();
        record.setUserId(situation.getUserId());
        record.setType(2);
        record.setCode(situation.getCode());
        record.setPrice(Long.valueOf(situation.getPrice()));
        record.setNftId(situation.getTokenId());
        record.setConsignId(id);
        record.setProdId(situation.getProdId());
        consignRecordService.save(record);

        PersonNft personNft = personNftService.getById(situation.getPositionId());

        if (personNft.getStatus() == 1) {
            personNftService.updatePersonNftStatus(Collections.singletonList(situation.getPositionId()), 0);
        } else if (personNft.getStatus() == 2) {
            // 资产转回到用户
            ConsignRecordVO recordVO = BeanUtil.copyProperties(record, ConsignRecordVO.class);
//            personnftFeignClient.consignIntoBillAndAsset(recordVO);
        } else {
            throw new YamiShopBindException("持仓状态异常");
        }
        RedisUtil.del("mallcloud:consign:submit:positionId" + "-" + situation.getPositionId());
    }

    @Override
    @Transactional
    public void offById(Long id, String userId) {
        ConsignSituation consign = getById(id);
        if(!userId.equals(consign.getUserId())){
            throw new YamiShopBindException("非法数据");
        }
        if (consign.getStatus() == ConsignStatus.CANCEL.getValue()) {
            throw new YamiShopBindException("已取消，不能操作！");
        }
        if (consign.getStatus() == ConsignStatus.SOLD.getValue()) {
            throw new YamiShopBindException("已出售，不能下架！");
        }
        if (consign.getSellStatus() != 0) {
            throw new YamiShopBindException("锁定中，不能下架！");
        }
        if (consign.getStatus() != ConsignStatus.CONSIGNMENT.getValue()) {
            throw new YamiShopBindException("只有寄售中的可以下架！");
        }
        consign.setStatus(ConsignStatus.USEROFF.getValue());
        updateById(consign);
    }


    @Override
    @Transactional
    public void audit(ConsignSituationVO situation, Integer sysType) {
        // 审核结果 1：同意 2：驳回
        Integer auditStatus = situation.getStatus();
        String auditReason = situation.getAuditReason();
        if (auditStatus == 2 && StringUtils.isEmpty(auditReason)) {
            throw new YamiShopBindException("驳回时，审核原因不能为空！");
        }
        ConsignSituation one = getById(situation.getId());
        ProdConfig prodConfig = prodConfigService.getOne(new LambdaQueryWrapper<ProdConfig>().eq(ProdConfig::getProdId, one.getProdId()).ne(ProdConfig::getStatus, ProdConsignStatus.DELETE.getValue()));
        if (Objects.isNull(prodConfig) || prodConfig.getStatus() != ProdConsignStatus.OPEN.getValue()) {
            throw new YamiShopBindException("该商品未开启寄售！");
        }
        if ((sysType == ConsignStatus.SHOP.getValue() && one.getShopAuditType() != ConsignStatus.MANUAL.getValue()) || (sysType == ConsignStatus.PLAT.getValue() && one.getAuditType() != ConsignStatus.MANUAL.getValue())) {
            throw new YamiShopBindException("只能对人工审核类型，进行审核！");
        }
        if (one.getStatus() != ConsignStatus.SHOPWAIT.getValue() && one.getStatus() != ConsignStatus.PLATWAIT.getValue()) {
            throw new YamiShopBindException("已审核不能重复审核！");
        }
        one.setAuditUser(situation.getAuditUser());
        Integer status = getStatusByAudit(sysType, one, auditStatus, auditReason);
        one.setStatus(status);
        if (status == ConsignStatus.CONSIGNMENT.getValue()) {
            addConsignRecord(one);
            one.setAuditTime(new Date());
            // 资产转移到担保账户
            transferToGuarantee(Arrays.asList(one));
        }
        updateById(one);
    }

    @Override
    @Transactional
    public void batchAudit(AuditParam param) {
        UserInfoInTokenBO tokenBO = AuthUserContext.get();
        Integer sysType = tokenBO.getSysType();
        Long userId = Long.valueOf(tokenBO.getUserId());
        if (CollUtil.isEmpty(param.getConsignIds())) {
            throw new YamiShopBindException("请选择要审核的寄售！");
        }
        Integer auditStatus = param.getStatus();
        String auditReason = param.getAuditReason();
        if (auditStatus == 2 && StringUtils.isEmpty(auditReason)) {
            throw new YamiShopBindException("驳回时，审核原因不能为空！");
        }
        List<Long> consignIds = param.getConsignIds();
        List<ConsignSituation> list = list(new LambdaQueryWrapper<ConsignSituation>().in(ConsignSituation::getId, consignIds));
        List<Integer> prodIds = list.stream().map(ConsignSituation::getProdId).distinct().collect(Collectors.toList());
        List<ProdConfig> consignProds = prodConfigService.list(new LambdaQueryWrapper<ProdConfig>().in(ProdConfig::getProdId, prodIds).ne(ProdConfig::getStatus, ProdConsignStatus.DELETE.getValue()));
        Map<Integer, ProdConfig> prodMap = consignProds.stream().collect(Collectors.toMap(ProdConfig::getProdId, Function.identity()));
        list.stream().forEach(a -> {
            if (Objects.isNull(prodMap.get(a.getProdId())) || prodMap.get(a.getProdId()).getStatus() != ProdConsignStatus.OPEN.getValue()) {
                throw new YamiShopBindException("商品【" + a.getProdName() + "】未开启寄售！");
            }
            if ((sysType == ConsignStatus.SHOP.getValue() && a.getShopAuditType() != ConsignStatus.MANUAL.getValue()) || (sysType == ConsignStatus.PLAT.getValue() && a.getAuditType() != ConsignStatus.MANUAL.getValue())) {
                throw new YamiShopBindException("只能对人工审核类型，进行审核！");
            }
            if (a.getStatus() != ConsignStatus.SHOPWAIT.getValue() && a.getStatus() != ConsignStatus.PLATWAIT.getValue()) {
                throw new YamiShopBindException("已审核不能重复审核！");
            }
            a.setAuditUser(userId);
            Integer status = getStatusByAudit(sysType, a, auditStatus, auditReason);
            a.setStatus(status);
            if (status == ConsignStatus.CONSIGNMENT.getValue()) {
                a.setAuditTime(new Date());
            }
        });
        updateBatchById(list);
        if (auditStatus == 1) {
            // 保存寄售记录
            List<ConsignSituation> adopts = list.stream().filter(c -> c.getStatus().equals(ConsignStatus.CONSIGNMENT.getValue())).collect(Collectors.toList());
            saveRecords(null, adopts);
            // 资产转移到担保账户adopts
            transferToGuarantee(adopts);
        }
    }

    /**
     * 获取审核后状态，保存审核记录
     *
     * @param sysType
     * @param one
     * @param auditStatus
     * @param auditReason
     * @return
     */
    private Integer getStatusByAudit(Integer sysType, ConsignSituation one, Integer auditStatus, String auditReason) {
        Integer status = null;
        if (one.getStatus() == ConsignStatus.SHOPWAIT.getValue()) {
            if (sysType == ConsignStatus.SHOP.getValue()) {
                saveAuditRecord(one, sysType, auditStatus, auditReason);
                if (auditStatus == 1) {
                    if (one.getAuditType() == ConsignStatus.MANUAL.getValue()) {
                        status = ConsignStatus.PLATWAIT.getValue();
                    } else {
                        if (one.getAuditType() == ConsignStatus.AUTOMATIC.getValue()) {
                            // 平台自动审核记录
                            one.setAuditUser(null);
                            saveAuditRecord(one, ConsignStatus.PLAT.getValue(), auditStatus, null);
                        }
                        status = ConsignStatus.CONSIGNMENT.getValue();
                    }
                } else {
                    status = ConsignStatus.SHOPREJECT.getValue();
                }
            } else {
                throw new YamiShopBindException("请商户审核");
            }
        }
        if (one.getStatus() == ConsignStatus.PLATWAIT.getValue()) {
            if (sysType == ConsignStatus.PLAT.getValue()) {
                saveAuditRecord(one, sysType, auditStatus, auditReason);
                if (auditStatus == 1) {
                    status = ConsignStatus.CONSIGNMENT.getValue();
                } else {
                    status = ConsignStatus.PLATREJECT.getValue();
                }
            } else {
                throw new YamiShopBindException("请平台审核");
            }
        }
        return status;
    }

    /**
     * 保存审核记录
     *
     * @param one
     * @param type
     * @param auditStatus
     * @param auditReason
     */
    private void saveAuditRecord(ConsignSituation one, Integer type, Integer auditStatus, String auditReason) {
        ConsignAuditRecord auditRecord = new ConsignAuditRecord();
        auditRecord.setConsignId(one.getId());
        auditRecord.setType(type);
        auditRecord.setPrice(one.getPrice());
        auditRecord.setAuditUser(one.getAuditUser());
        auditRecord.setStatus(auditStatus);
        auditRecord.setAuditReason(auditReason);
        auditRecord.setCreateTime(new Date());
        consignAuditRecordService.save(auditRecord);
    }

    /**
     * 资产转移到担保账户
     *
     * @param list
     */
    private void transferToGuarantee(List<ConsignSituation> list) {
        String chainCode = "";

        if (CollUtil.isEmpty(list)) {
            return;
        }

        List<String> positionIds = list.stream().map(ConsignSituation::getPositionId).collect(Collectors.toList());
        personNftService.updatePersonNftStatus(positionIds, 2);
        // 保存账单
        personNftAccountService.consignBill(positionIds);


        // 用户
        List<String> userIds = list.stream().map(ConsignSituation::getUserId).distinct().collect(Collectors.toList());
        // 获取用户链上地址助记词
        List<ChannelUserRelationRecord> chainUserList = channelUserRelationService.list(new LambdaQueryWrapper<ChannelUserRelationRecord>()
                .eq(ChannelUserRelationRecord::getChannelCode, "dtc").in(ChannelUserRelationRecord::getUserId, userIds).eq(ChannelUserRelationRecord::getChainCode, chainCode));
        Map<String, ChannelUserRelationRecord> userMap = chainUserList.stream().collect(Collectors.toMap(ChannelUserRelationRecord::getUserId, u -> u));

        log.info("寄售-资产转移到担保账户=======================数量：" + list.size());
        AssetTrendsEvent assetTrendsEvent = new AssetTrendsEvent();
        List<AssetTrendsVO> trendsList = new ArrayList<>();

        // 资产

        log.info("寄售-资产转移到担保账户结束=================");
        log.info("成功寄售：" + list.size() + "个，持仓id：" + positionIds.toString());
    }

    @Override
    public ConsignSituationVO getInfo(Long id) {
        ConsignSituation consignSituation = consignSituationMapper.selectById(id);
        ConsignSituationVO consignSituationVO = BeanUtil.copyProperties(consignSituation, ConsignSituationVO.class);
        return consignSituationVO;
    }

    @Override
    public Map<String, Object> getinfoById(Integer id) {
        ConsignSituation consign = consignSituationMapper.selectById(id);
        ConsignNumVO numByproductId = consignSituationMapper.getNumByproductId(consign.getProdId());
        Map<String, Object> oneDetail = new HashMap<>();
        oneDetail.put("id", consign.getId());
        oneDetail.put("prodId", consign.getProdId());
        oneDetail.put("img", consign.getImg());
        oneDetail.put("prodName", consign.getProdName());
        oneDetail.put("code", consign.getCode());
        oneDetail.put("prodCount", numByproductId.getProdCount()); // 在售
        oneDetail.put("allSum", numByproductId.getAllSum()); // 发行了
        oneDetail.put("denomId", consign.getDenomId());
        oneDetail.put("tokenId", consign.getTokenId());
        oneDetail.put("blockchain", "大唐链");
        oneDetail.put("price", consign.getPrice());
        Product product = productService.getById(consign.getProdId());
        ProdNft prodNft = prodNftService.getOne(new LambdaQueryWrapper<ProdNft>().eq(ProdNft::getProdId, consign.getProdId()).eq(ProdNft::getIsDel, 0));
        if (product != null) {
            oneDetail.put("author", prodNft.getAuthorName());  // 创作者
            oneDetail.put("authorImg", prodNft.getAuthorImg()); // 创作者头像
            oneDetail.put("level", prodNft.getLevelId());
            oneDetail.put("detail", product.getContent());
            Date createTime = product.getCreateTime();
            oneDetail.put("createTime", DateUtil.format(createTime, "yyyy/MM/dd"));
            oneDetail.put("shopId", product.getShopId());
            oneDetail.put("attr", prodNft.getAttr());
            oneDetail.put("type", product.getProdType());
            oneDetail.put("listImg", product.getImgs());
            oneDetail.put("backImg", product.getPic());
            oneDetail.put("shopName", prodNft.getIssueName());
            oneDetail.put("issue", prodNft.getIssueName());
            if (numByproductId.getCirculateNum() == 0) {
                // 获取流通量    类型盲盒
                if (product.getProdType() == 4) {
                    oneDetail.put("circulateNum", 0);
                }
                // 普通商品
                if (product.getProdType() == 0) {
                    oneDetail.put("circulateNum", 0);
                }
            } else {
                oneDetail.put("circulateNum", numByproductId.getCirculateNum()); // 流通
            }
        } else {
            oneDetail.put("author", null);
            oneDetail.put("authorImg", null);
            oneDetail.put("level", null);
            oneDetail.put("detail", null);
            oneDetail.put("createTime", null);
            oneDetail.put("shopId", null);
            oneDetail.put("attr", null);
            oneDetail.put("type", null);
            oneDetail.put("listImg", null);
            oneDetail.put("backImg", null);
            oneDetail.put("shopName", null);
            oneDetail.put("dawName", null);
            oneDetail.put("issue", null);
        }
        return oneDetail;
    }

    @Override
    public void updateConsignStatus(Long id, Integer status) {
        log.info("订单回调修改状态==================" + status);
        ConsignSituation situation = getById(id);
        situation.setStatus(status);
        int i = consignSituationMapper.updateById(situation);
        if (status == 5) {
            RedisUtil.del("mallcloud:consign:submit:positionId" + "-" + situation.getPositionId());
            log.info("已出售，删除寄售锁");
        }
        log.info("订单回调修改状态结束==================" + i);
    }

    @Override
    @Transactional
    public void orderConsignDown(OrderConsignUserDto orderConsignUser) {
        List<OrderConsignDto> orderConsignList = orderConsignUser.getOrderConsignVOList();
        String userId = orderConsignUser.getUserId();
        Long spuId = orderConsignUser.getSpuId();
        for (OrderConsignDto orderConsign : orderConsignList) {
            ConsignRecord one = consignRecordService.getOne(new LambdaQueryWrapper<ConsignRecord>().eq(ConsignRecord::getType, 1).eq(ConsignRecord::getNftId, orderConsign.getNftId())
                    .eq(ConsignRecord::getUserId, userId).eq(ConsignRecord::getConsignId, orderConsign.getConsignmentId()).eq(ConsignRecord::getProdId, spuId.intValue()));
            if (Objects.nonNull(one)) {
                log.error("已存在该用户此寄售买入记录：{}", JSON.toJSONString(one));
                continue;
            }
            ConsignRecordVO consignRecordVO = new ConsignRecordVO();
            consignRecordVO.setUserId(userId);
            consignRecordVO.setType(1);
            consignRecordVO.setNftId(orderConsign.getNftId());
            consignRecordVO.setCode(orderConsign.getConsignCode());
            consignRecordVO.setCreateTime(new Date());
            consignRecordVO.setConsignId(orderConsign.getConsignmentId());
            consignRecordVO.setPlatformCommission(orderConsign.getCommissionPlatform());
            consignRecordVO.setShopCommission(orderConsign.getCommissionShop());
            consignRecordVO.setPrice(orderConsign.getConsignPrice());
            consignRecordVO.setRealityPrice(orderConsign.getActualPrice());
            consignRecordVO.setProdId(spuId.intValue());
            consignRecordVO.setOrderId(orderConsign.getOrderId());
            Long aLong = consignRecordService.saveRecordVo(consignRecordVO);
            consignRecordVO.setId(aLong);
            // 资产转移到买家
//            ServerResponseEntity<Void> entity2 = personnftFeignClient.consignIntoBillAndAsset(consignRecordVO);

            log.info("寄售订单修改已售完结束");
            consignAnalysisService.update(spuId.intValue());
        }
    }

    @Override
    public Boolean updateSellStatus(Long id, Integer sellStatus) {
        Boolean bo = false;
        ConsignSituation situation = getById(id);
        if (situation.getStatus() == ConsignStatus.SOLD.getValue()) {
            return bo;
        } else if (situation.getStatus() == ConsignStatus.USEROFF.getValue()) {
            return bo;
        } else if (situation.getStatus() == ConsignStatus.CANCEL.getValue()) {
            return bo;
        }
        if (sellStatus == 1) {
            if (situation.getSellStatus() != 0) {
                return bo;
            }
        }
        log.info("订单回调修改状态解锁状态==================" + sellStatus);
        ConsignSituation consignSituation = new ConsignSituation();
        consignSituation.setSellStatus(sellStatus);
        consignSituation.setId(id);
        int i = consignSituationMapper.updateById(consignSituation);
        if (i > 0) {
            log.info("订单回调修改状态解锁状态结束==================" + sellStatus);
            return true;
        }
        return bo;
    }

    /**
     * 人工审核 寄售记录
     *
     * @param c
     */
    private void addConsignRecord(ConsignSituation c) {
        ConsignRecord record = new ConsignRecord();
        record.setUserId(c.getUserId());
        record.setType(0);
        record.setCode(c.getCode());
        record.setPrice(Long.valueOf(c.getPrice()));
        record.setNftId(c.getTokenId());
        record.setProdId(c.getProdId());
        record.setConsignId(c.getId());
        consignRecordService.save(record);
    }

    @Override
    public List<String> lockingConsignByTokenId(String tokenId) {
        List<ConsignSituation> list = list(new LambdaQueryWrapper<ConsignSituation>()
                .eq(ConsignSituation::getTokenId, tokenId).notIn(ConsignSituation::getStatus, ConsignStatus.SOLD.getValue(), ConsignStatus.CANCEL.getValue()));
        if (CollUtil.isEmpty(list)) {
            return null;
        }
        list.stream().forEach(c -> {
            c.setStatus(ConsignStatus.USEROFF.getValue());
            c.setSellStatus(2);
        });
        updateBatchById(list);
        List<String> userIds = list.stream().map(ConsignSituation::getUserId).collect(Collectors.toList());
        return userIds;
    }


}
